
# rd/rs1/rs2: [Register, ABI Name, Descrption, Saver]
gprs = {
    0x000: ['x0', 'zero', 'Zero Constant', '-'],
    0x001: ['x1', 'ra', 'Return address', 'Caller'],
    0x002: ['x2', 'sp', 'Stack pointer', '-'],
    0x003: ['x3', 'gp', 'Global pointer', '-'],
    0x004: ['x4', 'tp', 'Thread pointer', 'Callee'],
    0x005: ['x5', 't0', 'Temporary 0', 'Caller'],
    0x006: ['x6', 't1', 'Temporary 1', 'Caller'],
    0x007: ['x7', 't2', 'Temporary 2', 'Caller'],
    0x008: ['x8', 's0/fp', 'Saved register 0/frame pointer', 'Callee'],
    0x009: ['x9', 's1', 'Saved register 1', 'Callee'],
    0x00a: ['x10', 'a0', 'Fn arg 0', 'Caller'],
    0x00b: ['x11', 'a1', 'Fn arg 1', 'Caller'],
    0x00c: ['x12', 'a2', 'Fn arg 2', 'Caller'],
    0x00d: ['x13', 'a3', 'Fn arg 3', 'Caller'],
    0x00e: ['x14', 'a4', 'Fn arg 4', 'Caller'],
    0x00f: ['x15', 'a5', 'Fn arg 5', 'Caller'],
    0x010: ['x16', 'a6', 'Fn arg 6', 'Caller'],
    0x011: ['x17', 'a7', 'Fn arg 7', 'Caller'],
    0x012: ['x18', 's2', 'Saved register 2', 'Callee'],
    0x013: ['x19', 's3', 'Saved register 3', 'Callee'],
    0x014: ['x20', 's4', 'Saved register 4', 'Callee'],
    0x015: ['x21', 's5', 'Saved register 5', 'Callee'],
    0x016: ['x22', 's6', 'Saved register 6', 'Callee'],
    0x017: ['x23', 's7', 'Saved register 7', 'Callee'],
    0x018: ['x24', 's8', 'Saved register 8', 'Callee'],
    0x019: ['x25', 's9', 'Saved register 9', 'Callee'],
    0x01a: ['x26', 's10', 'Saved register 10', 'Callee'],
    0x01b: ['x27', 's11', 'Saved register 11', 'Callee'],
    0x01c: ['x28', 't3', 'Temporary 3', 'Caller'],
    0x01d: ['x29', 't4', 'Temporary 4', 'Caller'],
    0x01e: ['x30', 't5', 'Temporary 5', 'Caller'],
    0x01f: ['x31', 't5', 'Temporary 5', 'Caller'],
}

csrs = {
    0x0000: ['ustatus', 'User Status register'],
    0x0004: ['uie', 'User interrupt-enable register'],
    0x0005: ['utvec', 'User trap handler base address'],
    
    0x0040: ['uscratch', 'Scratch register for user trap handlers'],
    0x0041: ['uepc', 'User exception program counter'],
    0x0042: ['ucause', 'User trap cause'],
    0x0043: ['utval', 'User bad address or instruction'],
    0x0044: ['uip', 'User interrupt pending'],

    0x100: ['sstatus', ''],
    0x102: ['sedeleg', ''],
    0x103: ['sideleg', ''],
    0x104: ['sie', ''],
    0x105: ['stvec', ''],
    0x106: ['scounteren', ''],

    0x140: ['sscratch', ''],
    0x141: ['sepc', ''],
    0x142: ['scause', ''],
    0x143: ['stval', ''],
    0x144: ['sip', ''],

    0x180: ['satp', ''],

    0x300: ['mstatus', 'Machine Status register'],
    0x301: ['misa', 'ISA and extensions'],
    0x302: ['medeleg', 'Machine execution delegation register'],
    0x303: ['mideleg', 'Machine interrupt delegation register'],
    0x304: ['mie', 'Machine interrupt-enable register'],
    0x305: ['mtvec', 'Machine trap-handler base address'],
    0x306: ['mcounteren', 'Machine counter enable'],
    0x310: ['mstatush', 'Additional machine status register, RV32 only'],

    0x320: ['mcountinhibit', ''],
    0x323 : ['mhpmevent3', ''],
    0x324 : ['mhpmevent4', ''],
    0x325 : ['mhpmevent5', ''],
    0x326 : ['mhpmevent6', ''],

    0x340: ['mscratch', 'Scratch register for machine trap handlers'],
    0x341: ['mepc', 'Macine exception program counter'],
    0x342: ['mcause', 'Machine trap cause'],
    0x343: ['mtval', 'Machine bad address or instruction'],
    0x344: ['mip', 'Machine interrupt pending'],
    0x34a: ['mtinst', 'Machine trap instruction(transformed'],
    0x34b: ['mtval2', 'Machine bad guest physical address'],

    0x3a0: ['pmpcfg0', ''],
    0x3a1: ['pmpcfg1', ''],
    0x3a2: ['pmpcfg2', ''],
    0x3a3: ['pmpcfg3', ''],
    0x3b0: ['pmpaddr0', ''],
    0x3b1: ['pmpaddr1', ''],
    0x3b2: ['pmpaddr2', ''],
    0x3b3: ['pmpaddr3', ''],
    0x3b4: ['pmpaddr4', ''],
    0x3b5: ['pmpaddr5', ''],
    0x3b6: ['pmpaddr6', ''],
    0x3b7: ['pmpaddr7', ''],
    0x3b8: ['pmpaddr8', ''],
    0x3b9: ['pmpaddr9', ''],
    0x3ba: ['pmpaddr10', ''],
    0x3bb: ['pmpaddr11', ''],
    0x3bc: ['pmpaddr12', ''],
    0x3bd: ['pmpaddr13', ''],
    0x3be: ['pmpaddr14', ''],
    0x3bf: ['pmpaddr15', ''],


    0x07a0: ['tselect', 'Debug/Trace trigger register select'],
    0x07a1: ['tdata/mcontrol/icount/itrigger/etrigger', 'First Debug/Trace trigger data register'], 
    0x07a2: ['tdata2', 'Second Debug/Trace trigger data register'],
    0x07a3: ['tdata2/textra', 'Third Debug/Trace trigger data register'],
    0x07a4: ['tinfo', ''],
    0x07a5: ['tcontrol', ''],
    0x07a8: ['mcontext', 'Machine-mode context register'],
    0x07aa: ['scontext', ''],

    0x07b0: ['dcsr', 'Debug control and Status register'],
    0x07b1: ['dpc', ' Debug PC'],
    0x07b2: ['dscratch0', 'Debug scratch register 0'],
    0x07b3: ['dscratch1', 'Debug scratch register 1'],

    0x07c0: ['milmb', ''],
    0x07c1: ['mdlmb', ''],
    0x07c2: ['mecc_code', ''],
    0x07c0: ['mnvec', ''],
    0x07c4: ['mxstatus', ''],
    0x07c5: ['mpft_ctl', ''],
    0x07c6: ['mhsp_ctl', ''],
    0x07c7: ['msp_bound', ''],
    0x07c8: ['msp_base', ''],
    0x07c9: ['mdcause', ''],
    0x07ca: ['mcache_ctl', ''],
    0x07cb: ['mcctlbeginaddr', ''],
    0x07cc: ['mcctlcommand', ''],
    0x07cd: ['mcctldata', ''],


    0x07ce: ['mcounterwen', ''],
    0x07cf: ['mcounterinten', ''],
    0x07d0: ['mmisc_ctl', ''],
    0x07d1: ['mcountermask_m', ''],
    0x07d2: ['mcountermask_s', ''],
    0x07d3: ['mcountermask_u', ''],
    0x07d4: ['mcounterovf', ''],
    0x07d5: ['mslideleg', ''],

    0x07e0: ['dexc2dbg', ''],
    0x07e1: ['ddcause', ''],

    0x0800: ['uitb', ''],
    0x0801: ['ucode', ''],
    0x0809: ['udcause', ''],
    0x080b: ['ucctlbeginaddr', ''],
    0x080c: ['ucctlcommand', ''],

    0x09c4: ['slie', ''],
    0x09c5: ['slip', ''],
    0x09c9: ['sdcause', ''],
    0x09cd: ['scctldata', ''],
    0x09cf: ['scounterinten', ''],

    0x09d1: ['scountermask_m', ''],
    0x09d2: ['scountermask_s', ''],
    0x09d3: ['scountermask_u', ''],
    0x09d4: ['scounterovf', ''],
    0x09e0: ['scountinhibit', ''],
    0x09e3: ['shpmevent3', ''],
    0x09e4: ['shpmevent4', ''],
    0x09e5: ['shpmevent5', ''],
    0x09e6: ['shpmevent6', ''],


    0x0b00: ['mcycle', 'Machine cycle counter'],
    0x0b02: ['minstret', 'Machine instuctions-retired counter'],
    0x0b03: ['mhpmcounter3', ''],
    0x0b04: ['mhpmcounter4', ''],
    0x0b05: ['mhpmcounter5', ''],
    0x0b06: ['mhpmcounter6', ''],
    0x0b07: ['mhpmcounter7', ''],
    0x0b08: ['mhpmcounter8', ''],
    0x0b09: ['mhpmcounter9', ''],
    0x0b0a: ['mhpmcounter10', ''],
    0x0b0b: ['mhpmcounter11', ''],
    0x0b0c: ['mhpmcounter12', ''],
    0x0b0d: ['mhpmcounter13', ''],
    0x0b0e: ['mhpmcounter14', ''],
    0x0b0f: ['mhpmcounter15', ''],
    0x0b10: ['mhpmcounter16', ''],
    0x0b11: ['mhpmcounter17', ''],
    0x0b12: ['mhpmcounter18', ''],
    0x0b13: ['mhpmcounter19', ''],
    0x0b14: ['mhpmcounter20', ''],
    0x0b15: ['mhpmcounter21', ''],
    0x0b16: ['mhpmcounter22', ''],
    0x0b17: ['mhpmcounter23', ''],
    0x0b18: ['mhpmcounter24', ''],
    0x0b19: ['mhpmcounter25', ''],
    0x0b1a: ['mhpmcounter26', ''],
    0x0b1b: ['mhpmcounter27', ''],
    0x0b1c: ['mhpmcounter28', ''],
    0x0b1d: ['mhpmcounter29', ''],
    0x0b1e: ['mhpmcounter30', ''],
    0x0b1f: ['mhpmcounter31', ''],

    0xbc0: ['pmacfg0', ''],
    0xbc1: ['pmacfg1', ''],
    0xbc2: ['pmacfg2', ''],
    0xbc3: ['pmacfg3', ''],

    0xbd0: ['pmaaddr0', ''],
    0xbd1: ['pmaaddr1', ''],
    0xbd2: ['pmaaddr2', ''],
    0xbd3: ['pmaaddr3', ''],
    0xbd4: ['pmaaddr4', ''],
    0xbd5: ['pmaaddr5', ''],
    0xbd6: ['pmaaddr6', ''],
    0xbd7: ['pmaaddr7', ''],
    0xbd8: ['pmaaddr8', ''],
    0xbd9: ['pmaaddr9', ''],
    0xbda: ['pmaaddr10', ''],
    0xbdb: ['pmaaddr11', ''],
    0xbdc: ['pmaaddr12', ''],
    0xbdd: ['pmaaddr13', ''],
    0xbde: ['pmaaddr14', ''],
    0xbdf: ['pmaaddr15', ''],


    0x0f11: ['mvendorid', 'Vendor ID'],
    0x0f12: ['marchid', 'Architecutre ID'],
    0x0f13: ['mipid', 'Implementation ID'],
    0x0f14: ['mhartid', 'Hardware thread ID'],

    0x0fc0: ['micm_cfg', ''],
    0x0fc1: ['mdcm_cfg', ''],
    0x0fc2: ['mmsc_cfg', ''],

}

def get_gprinfo(gpr):
    gpr_attr = gprs.get(gpr, ['-', '-', '-', '-'])
    return gpr_attr[0] + '(' + gpr_attr[1] + ')'


# Funct3 : [inst, op]
def parse_opcode_0x33(data):
    rd = (data >> 7) & 0x1F
    funct3 = (data >> 12) & 7
    rs1 = (data >> 15) & 0x1F
    rs2 = (data >> 20) & 0x1F
    funct7 = (data >> 25) & 0x7F
    rd_str = get_gprinfo(rd)
    rs1_str = get_gprinfo(rs1)
    rs2_str = get_gprinfo(rs2)
    cmdStr = ''
    if (funct3 == 0):
        if (funct7 == 0):
            cmdStr += ('add: ' + rd_str + ' = ' + rs1_str + ' + ' + rs2_str)
        elif (funct7 == 0x20):
            cmdStr += ('sub: ' + rd_str + ' = ' + rs1_str + ' - ' + rs2_str)
    elif (funct3 == 4):
        if (funct7 == 0):
            cmdStr += ('xor: ' + rd_str + ' = ' + rs1_str + ' ^ ' + rs2_str)
    elif (funct3 == 6):
        if (funct7 == 0):
            cmdStr += ('or: ' + rd_str + ' = ' + rs1_str + ' | ' + rs2_str)
    elif (funct3 == 7):
        if (funct7 == 0):
            cmdStr += ('and: ' + rd_str + ' = ' + rs1_str + ' & ' + rs2_str)
    elif (funct3 == 1):
        if (funct7 == 0):
            cmdStr += ('sll: ' + rd_str + ' = ' + rs1_str + ' << ' + rs2_str)
    elif (funct3 == 5):
        if (funct7 == 0):
            cmdStr += ('srk: ' + rd_str + ' = ' + rs1_str + ' >> ' + rs2_str)
        elif (funct7 == 0x20):
            cmdStr += ('sra: ' + rd_str + ' = ' + rs1_str + ' >> ' + rs2_str)
    elif (funct3 == 2):
        if (funct7 == 0):
            cmdStr += ('slt: ' + rd_str + ' = (' + rs1_str + ' < ' + rs2_str + ') ? 1 : 0')
    elif (funct3 == 3):
        if (funct7 == 0):
            cmdStr += ('sltu: ' + rd_str + ' = (' + rs1_str + ' < ' + rs2_str + ') ? 1 : 0')
    else:
        cmdStr += ('Unknown command')
    return cmdStr

def parse_opcode_0x13(data):
    rd = (data >> 7) & 0x1F
    funct3 = (data >> 12) & 7
    rs1 = (data >> 15) & 0x1F
    imm = (data >> 20) & 0xFFF
    rd_str = get_gprinfo(rd)
    rs1_str = get_gprinfo(rs1)
    imm_str = hex(imm)
    cmdStr = ''
    if (funct3 == 0):
        cmdStr += ('addi: ' + rd_str + ' = ' + rs1_str + ' + ' + imm_str)
        if rd_str.startswith('x0') and rs1_str.startswith('x0'):
            cmdStr += '  Pseudo: nop'
        if imm == 0:
            cmdStr += '  Pseudo: mv ' + rd_str + ', ' + rs1_str
    elif (funct3 == 4):
        cmdStr += ('xori: ' + rd_str + ' = ' + rs1_str + ' ^ ' + imm_str)
    elif (funct3 == 6):
        cmdStr += ('ori: ' + rd_str + ' = ' + rs1_str + ' | ' + imm_str)
    elif (funct3 == 7):
        cmdStr += ('add: ' + rd_str + ' = ' + rs1_str + ' & ' + imm_str)
    elif (funct3 == 1):
        if (imm >>5) == 0:
            cmdStr += ('slli: ' + rd_str + ' = ' + rs1_str + ' << ' + hex(imm & 0x1F))
    elif (funct3 == 5):
        if (imm >> 5) == 0:
            cmdStr += ('srli: ' + rd_str + ' = ' + rs1_str + ' >> ' + hex(imm & 0x1F))
        elif (imm >>5) == 0x20:
            cmdStr += ('srai: ' + rd_str + ' = ' + rs1_str + ' >> ' + hex(imm & 0x1F))
    elif (funct3 == 2):
        cmdStr += ('slti: ' + rd_str + ' = (' + rs1_str + ' < ' + imm_str + ') ? 1 : 0')
    elif (funct3 == 3):
        cmdStr += ('sltiu: ' + rd_str + ' = (' + rs1_str + ' < ' + imm_str + ') ? 1 : 0')
    else:
        cmdStr += ('Unknown command')
    return cmdStr


def parse_opcode_0x03(data):
    rd = (data >> 7) & 0x1F
    funct3 = (data >> 12) & 7
    rs1 = (data >> 15) & 0x1F
    imm = (data >> 20) & 0xFFF
    rd_str = get_gprinfo(rd)
    rs1_str = get_gprinfo(rs1)
    imm_str = hex(imm)
    cmdStr = ''
    if (funct3 == 0):
        cmdStr += ('lb: ' + rd_str + ' = ' + 'M[' + rs1_str + ' + ' + imm_str + '][0:7]')
    elif (funct3 == 1):
        cmdStr += ('lh: ' + rd_str + ' = ' + 'M[' + rs1_str + ' + ' + imm_str + '][0:15]')
    elif (funct3 == 2):
        cmdStr += ('lw: ' + rd_str + ' = ' + 'M[' + rs1_str + ' + ' + imm_str + '][0:31]')
    elif (funct3 == 3):
        cmdStr += ('ld: ' + rd_str + ' = ' + 'M[' + rs1_str + ' + ' + imm_str + '][0:63]')
    elif (funct3 == 4):
        cmdStr += ('lbu: ' + rd_str + ' = ' + 'M[' + rs1_str + ' + ' + imm_str + '][0:7]')
    elif (funct3 == 5):
        cmdStr += ('lhu: ' + rd_str + ' = ' + 'M[' + rs1_str + ' + ' + imm_str + '][0:15]')
    elif (funct3 == 6):
        cmdStr += ('lwu: ' + rd_str + ' = ' + 'M[' + rs1_str + ' + ' + imm_str + '][0:31]')
    else:
        cmdStr += ('Unknown command')
    return cmdStr
    

def parse_opcode_0x23(data):
    immlo = (data >> 7) & 0x1F
    funct3 = (data >> 12) & 7 #
    rs1 = (data >> 15) & 0x1F 
    rs2 = (data >> 20) & 0x1F 
    immhi = (data >> 25) & 0x7F
    imm = (immhi << 5) | immlo
    rs1_str = get_gprinfo(rs1)
    rs2_str = get_gprinfo(rs2)
    cmdStr = ''
    if (funct3 == 0):
        cmdStr += ('sb: ' + 'M[' + rs1_str + ' + ' + hex(imm) + '][0:7] = ' + rs2_str + '[0:7]')
    elif (funct3 == 1):
        cmdStr += ('sh: ' + 'M[' + rs1_str + ' + ' + hex(imm) + '][0:15] = ' + rs2_str + '[0:15]')
    elif (funct3 == 2):
        cmdStr += ('sw: ' + 'M[' + rs1_str + ' + ' + hex(imm) + '][0:31] = ' + rs2_str + '[0:31]')
    elif (funct3 == 3):
        cmdStr += ('sd: ' + 'M[' + rs1_str + ' + ' + hex(imm) + '][0:63] = ' + rs2_str + '[0:63]')
    else:
        cmdStr += ('Unknown command')
    return cmdStr

# Branch instructions - B type
def parse_opcode_0x63(data):
    imm11 = (data >> 7) & 1
    imm4_1 = (data >> 8) & 0xF 
    funct3  = (data >> 12) & 0x7 
    rs1 = (data >> 15) & 0x1F 
    rs2 = (data >> 20) & 0x1F 
    imm10_5 = (data >> 25) & 0x7F
    imm12 = (data >> 31) & 1
    imm = (imm4_1<< 1) | (imm10_5 << 5) | (imm11 << 11) | (imm12 << 12) 
    rs1_str = get_gprinfo(rs1)
    rs2_str = get_gprinfo(rs2)
    cmdStr = ''
    if (funct3 == 0):
        cmdStr += ('beq: ' + 'if(' + rs1_str + '==' + rs2_str + ') PC += ' + hex(imm))
    elif (funct3 == 1):
        cmdStr += ('bne: ' + 'if(' + rs1_str + '!=' + rs2_str + ') PC += ' + hex(imm))
    elif (funct3 == 4):
        cmdStr += ('blt: ' + 'if(' + rs1_str + '<' + rs2_str + ') PC += ' + hex(imm))
    elif (funct3 == 5):
        cmdStr += ('bge: ' + 'if(' + rs1_str + '>=' + rs2_str + ') PC += ' + hex(imm))
    elif (funct3 == 6):
        cmdStr += ('bltu: ' + 'if(' + rs1_str + '<' + rs2_str + ') PC += ' + hex(imm))
    elif (funct3 == 7):
        cmdStr += ('bgeu: ' + 'if(' + rs1_str + '>=' + rs2_str + ') PC += ' + hex(imm))
    else:
        cmdStr += ('Unknown command')
    return cmdStr

def parse_opcode_0x6f(data):
    rd = (data >> 7) & 0x1F
    imm19_12 = (data >> 12) & 0xFF
    imm11 = (data >> 20) & 1
    imm10_1 = (data >> 21) & 0x3FF
    imm20 = (data >> 31) & 1
    imm = (imm10_1 << 1) | (imm11 << 11) | (imm19_12 << 12) | (imm20 << 20) 
    rd_str = get_gprinfo(rd)
    cmdStr = ('jal: ' + rd_str + ' = PC + 4; PC += ' + hex(imm))
    if (rd_str.startswith('x0')):
        cmdStr += '  Pseudo: j ' + hex(imm)
    elif (rd_str.startswith('x1')):
        cmdStr += '  Pseudo: jal ' + hex(imm)
    else:
        cmdStr += ('Unknown command')
    return cmdStr

def parse_opcode_0x67(data):
    rd = (data >> 7) & 0x1F
    funct3 = (data >> 12) & 7
    rs1 = (data >> 15) & 0x1F
    imm = (data >> 20) & 0xFFF
    rd_str = get_gprinfo(rd)
    rs1_str = get_gprinfo(rs1)
    imm_str = hex(imm)
    cmdStr = ''
    if (funct3 == 0):
        cmdStr += ('jalr: ' + rd_str + ' = PC + 4; PC = ' + rs1_str + ' + ' + hex(imm))
        if rd_str.startswith('x0') and imm == 0:
            cmdStr += '  Pseudo: jr ' + rs1_str
        if rd_str.startswith('x1') and imm == 0:
            cmdStr += '  Pseudo: jalr ' + rs1_str
        if rd_str.startswith('x0') and rs1_str.startswith('x1'):
            cmdStr += '  Pseudo: ret'
    else:
        cmdStr += ('Unknown command')
    return cmdStr

def parse_opcode_0x37(data):
    rd = (data >> 7) & 0x1F    
    imm = (data >> 12) & 0xFFFFF
    rd_str = get_gprinfo(rd)
    cmdStr = ('lui: ' + rd_str + ' = ' + hex(imm) + ' << 12')
    return cmdStr

def parse_opcode_0x17(data):
    rd = (data >> 7) & 0x1F    
    imm = (data >> 12) & 0xFFFFF
    rd_str = get_gprinfo(rd)
    cmdStr = ('auipc: ' + rd_str + ' = PC + (' + hex(imm) + ' << 12)')
    return cmdStr


def parse_opcode_0x73(data):
    rd = (data >> 7) & 0x1F
    funct3 = (data >> 12) & 7
    rs1 = (data >> 15) & 0x1F
    imm = (data >> 20) & 0xFFF
    rd_str = get_gprinfo(rd)
    rs1_str = get_gprinfo(rs1)
    imm_str = hex(imm)
    csr_str = csrs.get(imm, ['csr[' + hex(imm) + ']', 'TBD'])[0] # For CSR related Operations only
    cmdStr = ''
    if (funct3 == 0):
        if (imm == 0):
            cmdStr += ('ecall: Transfer control to OS')
        elif (imm == 1):
            cmdStr += ('ebreak: Transfer control to debugger')
        elif (imm == 0x7b2):
            cmdStr += ('dret')
        else:
            cmdStr += ('unknown instruction, to be added')
    elif (funct3 == 1): #CSRRW
        cmdStr += ('csrrw: ' + 'csrrw ' + rd_str + ', '  + csr_str + ', ' +rs1_str)
        if rd_str.startswith('x0'):
            cmdStr += '  <---> Pseudo: ' + csr_str + ' = ' + rs1_str
        else:
            cmdStr += '  <---> Pseudo: ' + rd_str + ' = ' + csr_str + '; ' + csr_str + ' = ' + rs1_str
    elif (funct3 == 2):#CSRRS
        cmdStr += ('csrrs: ' + 'csrrs ' + rd_str + ', '  + csr_str + ', ' +rs1_str)
        if (rs1_str.startswith('x0')):
            cmdStr += '  <---> Pseudo: ' + rd_str + ' = ' + csr_str
        else:
            cmdStr += '  <---> Pseudo: ' + rd_str + ' = ' + csr_str + '; ' + csr_str + '|= ' + rs1_str
    elif (funct3 == 3):#CSRRC
        cmdStr += ('csrrc: ' + 'csrrc ' + rd_str + ', '  + csr_str + ' ' +rs1_str)
        if (rs1_str.startswith('x0')):
            cmdStr += '  <---> Pseudo: ' + rd_str + ' = ' + csr_str
        else:
            cmdStr += '  <---> Pseudo: ' + rd_str + ' = ' + csr_str + '; ' + csr_str + '&= ~' + rs1_str
    elif (funct3 == 5):#CSRRWI
        ummi = rs1
        cmdStr += ('csrrwi: ' + 'csrrwi ' + rd_str + ', ' + csr_str + ', ' + hex(ummi))
        if rd_str.startswith('x0'):
            cmdStr += '  <---> Pseudo: ' + csr_str + '=' + hex(ummi)
        else:
            cmdStr += '  <---> Pseudo: ' + rd_str + ' = ' + csr_str + '; ' + csr_str + ' = ' + hex(ummi)
    elif (funct3 == 6):#CSRRSI
        ummi = rs1
        cmdStr += ('csrrsi: ' + 'csrrsi ' + rd_str + ', '  + csr_str + ', ' + hex(ummi))
        if ummi == 0:
            cmdStr += '  <---> Pseudo: ' + rd_str + ' = ' + csr_str + ')'
        else:
            cmdStr += '  <---> Pseudo: ' + rd_str + ' = ' + csr_str + '; ' + csr_str + ' |= ' + hex(ummi)  
    elif (funct3 == 7):#CSRRCI
        ummi = rs1
        cmdStr += ('csrrci ' + 'csrrci ' + rd_str + ', '  + csr_str + ', ' + hex(ummi))
        if (ummi == 0):#CSR
            cmdStr += '  <---> Pseudo: ' + rd_str + ' = ' + csr_str
        else:#CSR
            cmdStr += '  <---> Pseudo: ' + rd_str + ' = ' + csr_str + '; ' + csr_str + ' &= ~' + hex(ummi)

    else:
        cmdStr += ('unknown instruction, to be added')
    return cmdStr

def parse_opcode_0x0f(data):
    rd = (data >> 7) & 0x1F
    funct3 = (data >> 12) & 7
    rs1 = (data >> 15) & 0x1F
    fm = (data >> 28) & 0xF
    rd_str = get_gprinfo(rd)
    rs1_str = get_gprinfo(rs1)
    cmdStr = ''
    if (rd == 0):
        if (funct3 == 0):
            pred = (data >> 24) & 0xF  
            succ = (data >> 20) & 0xF 
            cmdStr += ('fence, successor = ' + str(succ) + ", predecessor = " + str(pred))
        elif (funct3 == 1):
            cmdStr += ('fence.i')
    else:
        cmdStr += ('Unknown command')
    return cmdStr
    

def parse_opcode_0x2f(data):
    rd = (data >> 7) & 0x1F
    funct3 = (data >> 12) & 7
    rs1 = (data >> 15) & 0x1F
    rs2 = (data >> 20) & 0x1F
    rl = (data >> 25) & 1
    aq = (data >> 26) & 1
    funct5 = (data >> 27) & 0x1F
    rd_str = get_gprinfo(rd)
    rs1_str = get_gprinfo(rs1)
    rs2_str = get_gprinfo(rs2)
    cmdStr = ''
    if (funct3 == 2):
        if (funct5 == 2):
            cmdStr = ('lr.w: ' + rd_str + ' M[' + rs1_str + '], reserve M[' + rs1_str + ']')
        elif (funct5 == 3):
            cmdStr = ('sc.w: ' + 'if (reserved) { M['+ rs1_str + '] = ' + rs2_str + '; ' + rd_str + ' = 0} else {' + rd_str + ' = 1}')
        elif (funct5 == 1):
             cmdStr = ('amoswap.w: ' + rd_str + ' = M[' + rs1_str + ']; swap(' + rd_str + ', ' + rs2_str + '); M[' + rs1_str + '] = ' + rd_str)
        elif (funct5 == 0):
            cmdStr = ('amoadd.w: ' + rd_str + ' = M[' + rs1_str + '] + ' + rs2_str + '; M[ ' + rs1_str + '] = ' + rd_str)
        elif (funct5 == 0xc):
            cmdStr = ('amoadd.w: ' + rd_str + ' = M[' + rs1_str + '] & ' + rs2_str + '; M[ ' + rs1_str + '] = ' + rd_str)
        elif (funct5 == 0xa):
            cmdStr = ('amoor.w: ' + rd_str + ' = M[' + rs1_str + '] | ' + rs2_str + '; M[ ' + rs1_str + '] = ' + rd_str)
        elif (funct5 == 0x4):
            cmdStr = ('amoxor.w: ' + rd_str + ' = M[' + rs1_str + '] ^ ' + rs2_str + '; M[ ' + rs1_str + '] = ' + rd_str)
        elif (funct5 == 0x14):
            cmdStr = ('amomax.w: ' + rd_str + ' = max(M[' + rs1_str + '], ' + rs2_str + '); M[ ' + rs1_str + '] = ' + rd_str)
        elif (funct5 == 0x10):
            cmdStr = ('amomin.w: ' + rd_str + ' = min(M[' + rs1_str + '], ' + rs2_str + '); M[ ' + rs1_str + '] = ' + rd_str)
    else:
        cmdStr = 'unsupported yet, to be added'
    return cmdStr


def parse_rv32c_inst(data):
    op = data & 3
    pass

def parse_rv32_inst(data):
    cmdStr = '' #TODO:
    # Standard Extension
    if (data & 0xfffff) == 0xfffff:
        return cmdStr
    if (data & 0x3) == 0x3:
        opcode = data & 0x7F
        if (opcode == 0x33):
            cmdStr = parse_opcode_0x33(data)
        elif (opcode == 0x13):
            cmdStr = parse_opcode_0x13(data)
        elif (opcode == 0x03):
            cmdStr = parse_opcode_0x03(data)
        elif (opcode == 0x23):
            cmdStr = parse_opcode_0x23(data)
        elif (opcode == 0x13):
            cmdStr = parse_opcode_0x13(data)
        elif (opcode == 0x63):
            cmdStr = parse_opcode_0x63(data)
        elif (opcode == 0x6f):
            cmdStr = parse_opcode_0x6f(data)
        elif (opcode == 0x37):
            cmdStr = parse_opcode_0x37(data)
        elif (opcode == 0x67):
            cmdStr = parse_opcode_0x67(data)
        elif (opcode == 0x17):
            cmdStr = parse_opcode_0x17(data)
        elif (opcode == 0x73):
            cmdStr = parse_opcode_0x73(data)
        elif (opcode == 0x0F):
            cmdStr = parse_opcode_0x0f(data)
        elif (opcode == 0x2f): #RV32A ISA
            cmdStr = parse_opcode_0x2f(data)
        else:
            cmdStr = 'Unsupported instruction yet, to be added' #TODO:
    #Compressed Extension
    elif (data & 0x3) != 0x3:
        cmdStr = 'Unsupported  compressed instruction' #TODO:
    if len(cmdStr) > 0:
        cmdStr = ('\n        ') + cmdStr
    return cmdStr